#region Copyright (c) 2006-2010 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2010 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Text;
using System.Xml;
using System.Linq;
using System.ComponentModel;
using System.Collections;
using Widgetsphere.Generator.Common.GeneratorFramework;
using Widgetsphere.Generator.Common.Util;
using System.Collections.Generic;
using Widgetsphere.Generator.ProjectItemGenerators;
using System.Collections.ObjectModel;

namespace Widgetsphere.Generator.Models
{
  [
  Designer(typeof(Widgetsphere.Generator.Design.Designers.TableDesigner)),
  DesignTimeVisible(true),
  ]
  public class Table : BaseModelObject, ICodeFacadeObject
  {
    #region Member Variables

		public enum UnitTestSettingsConstants
		{
			//NoTest,
			StubOnly,
			FullTest,
		}

    protected const bool _def_associativeTable = false;
    protected const bool _def_generated = true;
    protected const bool _def_hasHistory = false;
    protected const bool _def_modifiedAudit = true;
    protected const bool _def_createAudit = true;
    protected const bool _def_timestamp = true;
    protected const bool _def_isTypeTable = false;
    protected const bool _def_createMetaData = false;
		protected const bool _def_fullIndexSearch = false;		
		protected const bool _def_allowAuditTracking = false;
		protected const bool _def_immutable = false;
		protected const bool _def_enforePrimaryKey = true;
		protected const string _def_dbSchema = "dbo";
		protected const UnitTestSettingsConstants _def_allowUnitTest = UnitTestSettingsConstants.StubOnly;

    protected int _id = 1;
		protected string _name = "";
    protected string _codeFacade = "";
    protected string _description = "";
    protected bool _associativeTable = _def_associativeTable;
    protected bool _generated = _def_generated;
    protected bool _hasHistory = _def_hasHistory;
    protected bool _modifiedAudit = _def_modifiedAudit;
    protected bool _createAudit = _def_createAudit;
    protected bool _allowTimestamp = _def_timestamp;
    protected bool _isTypeTable = _def_isTypeTable;
    protected bool _createMetaData = _def_createMetaData;
    protected bool _fullIndexSearch = _def_fullIndexSearch;
    protected RowEntryCollection _staticData = null;
    protected ReferenceCollection _columns = null;
    protected ReferenceCollection _relationships = null;
    protected ReferenceCollection _customRetrieveRules = null;
    private bool _isMetaData = false;
    private bool _isMetaDataDefinition = false;
		private bool _isMetaDataMaster = false;
		private DateTime _createdDate = DateTime.Now;
		private string _parentTableKey = null;		
		private UnitTestSettingsConstants _allowUnitTest = _def_allowUnitTest;
		private List<Table> _unitTestDependencies = new List<Table>();
		private List<int> _unitTestTableIdPreLoad = new List<int>();
		private TableCompositeCollection _compositeList = null;
		private TableComponentCollection _componentList = null;
		private bool _allowAuditTracking = _def_allowAuditTracking;
		private bool _immutable = _def_immutable;
		private bool _enforePrimaryKey = _def_enforePrimaryKey;
		private string _dbSchema = _def_dbSchema;

    #endregion

    #region Constructors

    public Table(IModelObject root)
      : base(root)
    {
			_compositeList = new TableCompositeCollection(root, this);
			_componentList = new TableComponentCollection(root, this);

      _staticData = new RowEntryCollection(this.Root);
      _columns = new ReferenceCollection(this.Root, this, ReferenceType.Column);
      _customRetrieveRules = new ReferenceCollection(this.Root, this, ReferenceType.CustomRetrieveRule);
      _relationships = new ReferenceCollection(this.Root, this, ReferenceType.Relation);

      _columns.ObjectPlural = "Columns";
      _columns.ObjectSingular = "Column";
      _columns.ImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderClose);
      _columns.SelectedImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderOpen);

      _customRetrieveRules.ObjectPlural = "RetrieveRules";
      _customRetrieveRules.ObjectSingular = "RetrieveRule";
      _customRetrieveRules.ImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderClose);
      _customRetrieveRules.SelectedImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderOpen);      

      _relationships.ObjectPlural = "Relationships";
      _relationships.ObjectSingular = "Relationship";
      _relationships.ImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderClose);
      _relationships.SelectedImageIndex = ImageHelper.GetImageIndex(ImageConstants.FolderOpen);


    }

    #endregion

    #region Property Implementations

		[Browsable(false)]
		public bool NeedOverridePersistable
		{
			get
			{
				List<Table> tableList = this.GetTableHierarchy();
				tableList.RemoveAt(tableList.Count - 1);
				bool allowModification = false;
				foreach (Table t in tableList)
				{
					allowModification |= !t.Immutable;
				}
				return allowModification;
			}
		}

		[
		Browsable(false),
		Description("Creates a hierarchy of dependencies for unit test generation."),
		Category("Data"),
		//TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.UnitTestDependencyConverter)),
		//Editor(typeof(Widgetsphere.Generator.Design.Editors.UnitTestDependencyEditor), typeof(System.Drawing.Design.UITypeEditor))
		]
		public List<Table> UnitTestDependencies
		{
			get { return _unitTestDependencies; }
		}

		[
		Browsable(false),
		Description("A list of composite objects of this table."),
		Category("Relations"),
		]
		public TableCompositeCollection CompositeList
		{
			get { return _compositeList; }
		}

		[
		Browsable(false),
		Description("A list of component objects of this table. These are sub-tables that are created in the API with a subset of columns from this table."),
		Category("Relations"),
		]
		public TableComponentCollection ComponentList
		{
			get { return _componentList; }
		}		

		[
		Browsable(false),
		Description("Determines if unit tests are generated for this object."),
		Category("Behavior"),
		DefaultValue(typeof(UnitTestSettingsConstants), "StubOnly"),
		]
		public UnitTestSettingsConstants AllowUnitTest
		{
			get
			{
				if (!this.Immutable)
					return _allowUnitTest;
				else //If the table cannot be modified then no unit test
					return UnitTestSettingsConstants.StubOnly;
			}
			set
			{
				_allowUnitTest = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("AllowUnitTest"));
			}
		}
	

		[
		Browsable(true),
		Description("Determines if there is a parent table from which this object is inherited."),
		Editor(typeof(Widgetsphere.Generator.Design.Editors.ParentTableSelectEditor), typeof(System.Drawing.Design.UITypeEditor)),
		Category("Data"),
		]
		public Table ParentTable
		{
			get
			{
				Table[] arr = ((ModelRoot)this.Root).Database.Tables.GetByKey(_parentTableKey);
				if (arr.Length == 0) return null;
				else return arr[0];
			}
			set
			{
				if (value == null)
				{
					if (_parentTableKey != null)
					{
						_parentTableKey = null;
						this.OnPropertyChanged(this, new PropertyChangedEventArgs("ParentTable"));
					}
				}
				else
				{
					//Ensure that there are no circles
					List<Table> tList = value.GetTableHierarchy();
					if (tList.Contains(this))
					{
						throw new Exception("This table cannot inherit from the specified table as it would create a circular inheritance.");
					}

					if (_parentTableKey != value.Key)
					{
						_parentTableKey = value.Key;
						this.OnPropertyChanged(this, new PropertyChangedEventArgs("ParentTable"));
					}
				}
				
			}
		}

		[Browsable(false)]
		public string ParentTableKey
		{
			get { return _parentTableKey; }
			private set
			{
				_parentTableKey = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("ParentTableKey"));
			}
		}

    [
    Browsable(true),
    Description("Determines if this table will be used to generate an enumeration."),
    Category("Data"),
    DefaultValue(_def_isTypeTable),
    ]
    public bool IsTypeTable
    {
      get { return _isTypeTable; }
      set
      {
        _isTypeTable = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("IsTypeTable"));
      }
    }

    [
    Browsable(true),
    Description("Determines the name of this table."),
    Category("Design"),
    DefaultValue("")
    ]
    public string Name
    {
      get { return _name; }
      set
      {
        _name = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Name"));
      }
    }

    [
    Browsable(true),
		Description("Determines the parent schema for this object."),
    Category("Design"),
		DefaultValue(_def_dbSchema)
    ]
		public string DBSchema
    {
			get { return _dbSchema; }
      set
      {
				_dbSchema = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("DBSchema"));
      }
    }

    [
    Browsable(true),
    Description("The description of this table."),
    Category("Data"),
    DefaultValue(""),
    ]
    public string Description
    {
      get { return _description; }
      set
      {
        _description = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Description"));
      }
    }

    [
    Browsable(true),
    Description("Determines if items from this table are readonly. When true items cannot be modified."),
    Category("Data"),
		DefaultValue(_def_immutable),
    ]
		public bool Immutable
    {
			get { return _immutable; }
      set
      {
				_immutable = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("Immutable"));
      }
    }		

    [
    Browsable(true),
    Description("This collection defines the relationships in which this table participates."),
		Category("Relations"),
    TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.RelationCollectionConverter)),
    Editor(typeof(Widgetsphere.Generator.Design.Editors.RelationReferenceCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))
    ]
    public ReferenceCollection Relationships
    {
      get
      {
        try
        {
					return _relationships;
        }
        catch(Exception ex)
        {
          throw;
        }
      }
    }

		/// <summary>
		/// Returns a list of all parent and child relations
		/// </summary>
    [Browsable(false)]
    public RelationCollection AllRelationships
    {
      get
      {
        RelationCollection retval = new RelationCollection(this.Root);
        RelationCollection relationCollection = ((ModelRoot)this.Root).Database.Relations;
        foreach(Relation r in relationCollection)
        {
          if((r.ParentTableRef != null) && (r.ChildTableRef != null))
          {
						if ((r.ParentTableRef.Ref == this.Id) || (r.ChildTableRef.Ref == this.Id))
            {
              retval.Add(r);
            }
          }
        }
        return retval;
      }
    }

    [
		Browsable(false),
    Description("The list of columns that are associated with this table."),
    Category("Data"),
    TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.ColumnReferenceCollectionConverter)),
    Editor(typeof(Widgetsphere.Generator.Design.Editors.ColumnReferenceCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))
    ]
    public ReferenceCollection Columns
    {
      get { return _columns; }
    }

    [
    Browsable(false),
    Description("A list of custom retrieve rules that can be run against this table."),
		Category("Relations"),
    TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.ColumnReferenceCollectionConverter)),
    Editor(typeof(Widgetsphere.Generator.Design.Editors.ColumnReferenceCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))
    ]
    public ReferenceCollection CustomRetrieveRules
    {
      get { return _customRetrieveRules; }
    }

		/// <summary>
		/// Returns the generated columns for this table only (not hierarchy)
		/// </summary>
		[Browsable(false)]
		public IEnumerable<Column> GeneratedColumns
		{
			get
			{
				return this.GetColumns()
					.Where(x => x.Generated)
					.OrderBy(x => x.Name);
			}
		}

    [Browsable(false)]
    public ReferenceCollection GeneratedRetrieveRules
    {
      get
      {
        ReferenceCollection retVal = new ReferenceCollection(this.Root);
        foreach(Reference reference in _customRetrieveRules)
        {
          CustomRetrieveRule dc = (CustomRetrieveRule)reference.Object;
          if(dc.Generated)
            retVal.Add(dc.CreateRef());
          else
            System.Diagnostics.Debug.Write("");
        }
        return retVal;
      }
    }

    [
    Browsable(true),
    Description("Determines if this item is used in the generation."),
    Category("Data"),
    DefaultValue(_def_generated),
    ]
    public bool Generated
    {
      get { return _generated; }
      set
      {
        _generated = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Generated"));
      }
    }

    [
    Browsable(true),
    Description("Determines if the fields 'ModifiedBy' and 'ModifiedDate' are created."),
		Category("Behavior"),
    DefaultValue(_def_modifiedAudit),
    ]
    public bool AllowModifiedAudit
    {
			get { return _modifiedAudit && !((ModelRoot)Root).Database.AllowZeroTouch; }
      set
      {
        _modifiedAudit = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("modifiedAudit"));
      }
    }

    [
    Browsable(true),
		Category("Behavior"),
    Description("Determines if the fields 'CreateBy' and 'CreateDate' are created."),
    DefaultValue(_def_createAudit),
    ]
    public bool AllowCreateAudit
    {
			get { return _createAudit && !((ModelRoot)Root).Database.AllowZeroTouch; }
      set
      {
        _createAudit = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("createAudit"));
      }
    }

    [
    Browsable(true),
    Description("Determines if this table will have a timestamp field created and used for synchronization."),
		Category("Behavior"),
    DefaultValue(_def_timestamp),
    ]
    public bool AllowTimestamp
    {
			get { return _allowTimestamp && !((ModelRoot)Root).Database.AllowZeroTouch; }
      set
      {
        _allowTimestamp = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Timestamp"));
      }
    }

		[Browsable(true),
    Description("Determines if this primary key is enforced in the database."),
    Category("Data"),
		DefaultValue(_def_enforePrimaryKey),
		]
		public bool EnforcePrimaryKey
		{
			get { return _enforePrimaryKey; }
			set { _enforePrimaryKey = value; }
		}

		[Browsable(false)]
		public bool IsAuditable
		{
			get { return this.AllowCreateAudit || this.AllowModifiedAudit || this.AllowTimestamp; }
		}

		/// <summary>
		/// This not implemented
		/// </summary>
    [
    Browsable(false),
    Description("Determines if this table should implement a full index search."),
    Category("Data"),
    DefaultValue(_def_fullIndexSearch),
    ]
    public bool FullIndexSearch
    {
      get { return _fullIndexSearch; }
      set
      {
        _fullIndexSearch = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("FullIndexSearch"));
      }
    }

    [Browsable(false)]
    public int Id
    {
      get { return _id; }
    }

    [
    Browsable(true),
    Description("Defines the static data that is generated into the database scripts."),
    Category("Data"),
    TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.RowEntryCollectionConverter)),
    ]
    public RowEntryCollection StaticData
    {
      get { return _staticData; }
    }

    [
    Browsable(true),
    Description("Determines if this is an intermediary table between two other tables."),
    Category("Data"),
    DefaultValue(_def_associativeTable),
    ]
    public bool AssociativeTable
    {
      get { return _associativeTable; }
      set
      {
        _associativeTable = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("associativeTable"));
      }
    }

		[
		Browsable(true),
		Description("Determines if audit tables are created in the database that will log an audit trail of records for this table."),
		Category("Behavior"),
		DefaultValue(_def_allowAuditTracking),
		]
		public bool AllowAuditTracking
		{
			get { return _allowAuditTracking; }
			set
			{
				_allowAuditTracking = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("allowAuditTracking"));
			}
		}

		/// <summary>
		/// This not implemented
		/// </summary>
		[
    Browsable(false),
    Description("Determines if history tables are generated."),
		Category("Behavior"),
    DefaultValue(_def_hasHistory),
    ]
    public bool HasHistory
    {
      get { return _hasHistory; }
      set
      {
        _hasHistory = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("hasHistory"));
      }
    }

		/// <summary>
		/// This not implemented
		/// </summary>
		[
    Browsable(false),
    Description("Determines if meta data tables are generated."),
    Category("Data"),
    DefaultValue(_def_createMetaData),
    ]
    public bool CreateMetaData
    {
      get { return _createMetaData; }
      set
      {
        _createMetaData = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("createMetaData"));
      }
    }

		[Browsable(false)]
    internal bool IsMetaData
    {
      get { return _isMetaData; }
      set { _isMetaData = value; }
    }

		[Browsable(false)]
    public bool IsMetaDataDefinition
    {
      get { return _isMetaDataDefinition; }
      set { _isMetaDataDefinition = value; }
    }

    internal bool IsMetaDataMaster
    {
      get { return _isMetaDataMaster; }
      set { _isMetaDataMaster = value; }
    }

		[Browsable(false)]
		public bool InheritsCreateAudit
		{
			get
			{
				List<Table> tables = this.GetTableHierarchy();
				if (tables.Contains(this))
					tables.Remove(this);

				return ((from x in tables
								 where x.AllowCreateAudit == true
								 select x).ToArray().Length != 0);

			}
		}

		[Browsable(false)]
		public bool InheritsModifyAudit
		{
			get
			{
				List<Table> tables = this.GetTableHierarchy();
				if (tables.Contains(this))
					tables.Remove(this);

				return ((from x in tables
								 where x.AllowModifiedAudit == true
								 select x).ToArray().Length != 0);

			}
		}

    #endregion

    #region Methods

		public bool FullHierarchyPrimaryKeyIsDatabaseIdentity()
		{
			Table t = this;
			while (t != null)
			{
				foreach (Column column in t.PrimaryKeyColumns.OrderBy(x => x.Name))
				{
					if (column.Identity == IdentityTypeConstants.Database)
						return true;
				}
				t = t.ParentTable;
			}
			return false;
		}

		/// <summary>
		/// Get all relations where this table or any derived table is the child
		/// </summary>
		/// <returns></returns>
		public IEnumerable<Relation> GetChildRoleRelationsFullHierarchy()
		{			
			List<Relation> retval = new List<Relation>();
			foreach (Table table in this.GetTableHierarchy())
			{
				foreach (Relation relation in table.ChildRoleRelations)
				{
					if ((relation.ChildTableRef.Object != null) && (relation.ChildTableRef.Ref == table.Id))
						retval.Add(relation);
				}
			}
			return retval;
		}

		/// <summary>
		/// Get all relations where this table or any derived table is the parent
		/// </summary>
		/// <returns></returns>
		public IEnumerable<Relation> GetParentRoleRelationsFullHierarchy()
		{
			List<Relation> retval = new List<Relation>();
			foreach (Table table in this.GetTableHierarchy())
			{
				foreach (Relation relation in table.ParentRoleRelations)
				{
					if ((relation.ParentTableRef.Object != null) && (relation.ParentTableRef.Ref == table.Id))
						retval.Add(relation);
				}
			}
			return retval;
		}

		public void AddUnitTests()
		{
			this.AllowUnitTest = UnitTestSettingsConstants.FullTest;

			List<Table> leftOverTables = null;
			List<Table> usedList = new List<Table>(this.UnitTestDependencies);
			usedList.Reverse();

			//while (leftOverTables == null || leftOverTables.Count > 0)
			//{
				//Get a list of all child tables so we can query parents
				List<Table> childTableList = new List<Table>();
				childTableList.AddRange(this.GetTableHierarchy());
				foreach (Table t in usedList)
				{
					childTableList.AddRange(t.GetTableHierarchy());
				}

				//Get a list of all used tables
				List<Table> list = new List<Table>();
				foreach (Table t in childTableList)
				{
					foreach (Table c in t.GetParentTables())
						if (!list.Contains(c)) list.Add(c);
				}

				IEnumerable<Table> list1 = (from x in list select x).Distinct();
				IEnumerable<Table> list2 = (from x in childTableList select x).Distinct();

				leftOverTables = new List<Table>(list1.Except(list2));
				usedList.AddRange(leftOverTables);
			//}

			//Now set the Dependencies to the new list
			this.UnitTestDependencies.Clear();
			usedList.Reverse();
			this.UnitTestDependencies.AddRange(usedList);

		}

    public override string ToString()
    {
      string retval = this.Name;
			//if(this.CodeFacade != "")
			//  retval += " AS " + this.CodeFacade;
			return retval;
    }

    protected internal System.Data.DataTable CreateDataTable()
    {
      System.Data.DataSet retval = new System.Data.DataSet();
      System.Data.DataTable t = retval.Tables.Add(this.Name);
      foreach(Reference reference in this.Columns)
      {
        Column column = (Column)reference.Object;
        System.Data.DataColumn c = t.Columns.Add(column.Name, typeof(string));
      }      
      return retval.Tables[0];
    }

		public List<Column> GetColumnsSearchable()
		{
			return GetColumnsSearchable(false);
		}

		public List<Column> GetColumnsSearchable(bool fullHeirarchy)
		{
			IEnumerable colList = null;
			if (fullHeirarchy) colList = this.GetColumnsFullHierarchy();
			else colList = this.GetColumns();

			List<Column> retval = new List<Column>();
			foreach (Column c in colList)
			{				
				if (c.IsSearchable)
					retval.Add(c);
			}
			return retval;
		}

		public string GetFullHierarchyTableJoin()
		{
			return GetFullHierarchyTableJoin(false);
		}

		public string GetFullHierarchyTableJoin(bool useLinqAlias)
		{
			string t1Name = "[" + this.DatabaseName + "]";
			string t1NameClause = "";
			string t1Alias = "[t0]";
			if (useLinqAlias) t1NameClause = t1Name + " AS " + t1Alias;
			else t1NameClause = t1Name;

			int tableIndex = 1;
			string retval = t1NameClause;
			Table t = this.ParentTable;
			while (t != null)
			{
				string t2Name = "[" + t.DatabaseName + "]";
				string t2NameClause = "";
				string t2Alias = "[z" + tableIndex + "]";

				if (useLinqAlias) t2NameClause = t2Name + " AS " + t2Alias;
				else t2NameClause = t2Name;
				retval += " INNER JOIN " + t2NameClause + " ON ";
				int index = 0;
				foreach (Column c in t.PrimaryKeyColumns.OrderBy(x => x.Name))
				{
					index++;
					retval += " " + (useLinqAlias ? t1Alias : t1Name) + ".[" + c.DatabaseName + "] = " + (useLinqAlias ? t2Alias : t2Name) + ".[" + c.DatabaseName + "]";
					if (index < t.PrimaryKeyColumns.Count)
						retval += ", ";
				}
				t = t.ParentTable;
				tableIndex++;

				t1Name = t2Name;
				t1NameClause = t2NameClause;
				t1Alias = t2Alias;
			}
			return retval;
		}

		/// <summary>
		/// Determines if the specified table is an ancestor of the this table object
		/// </summary>
		/// <param name="table"></param>
		/// <returns></returns>
		public bool IsInheritedFrom(Table table)
		{
			Table t = this.ParentTable;
			while (t != null)
			{
				if (t == table) return true;
				t = t.ParentTable;
			}
			return false;
		}

		/// <summary>
		/// Determines if this table shares a common ancestor with the specified table
		/// </summary>
		/// <param name="table"></param>
		/// <returns></returns>
		public bool ShareAncestor(Table table)
		{
			if (table == null) return false;
			if (table == this) return false;

			List<Table> list1 = this.GetTableHierarchy();
			List<Table> list2 = table.GetTableHierarchy();
			return (list1.Intersect(list2).Count() > 0);
		}

		/// <summary>
		/// Get all the tables that are descendants of this table
		/// </summary>
		/// <returns></returns>
		public List<Table> GetTablesInheritedFromHierarchy()
		{
			List<Table> retval = new List<Table>();
			retval.Add(this);
			int count = retval.Count;

			do
			{
				count = retval.Count;
				foreach (Table t in ((ModelRoot)this.Root).Database.Tables)
				{
					List<Table> addedItems = new List<Table>();
					foreach (Table t2 in retval)
					{
						if (t.ParentTable == t2)
						{
							if (!retval.Contains(t))
								addedItems.Add(t);
						}
					}
					retval.AddRange(addedItems);
				}
			} while (count != retval.Count);

			//Remove this table
			retval.RemoveAt(0);
			return retval;
		}

		[Browsable(false)]
		public bool IsValidInheritance
		{
			get
			{
				List<Table> inheritTables = new List<Table>();
				inheritTables = this.GetTableHierarchy();

				Dictionary<string, Column> pkList = new Dictionary<string, Column>();
				foreach (Column c in this.PrimaryKeyColumns.OrderBy(x => x.Name))
				{
					pkList.Add(c.Name.ToLower(), c);
				}

				//Ensure that all tables have the same primary keys
				foreach (Table t in inheritTables)
				{
					if (t.PrimaryKeyColumns.Count != this.PrimaryKeyColumns.Count)
					{
						//Different number of pk columns so invalid
						return false;
					}
					else
					{
						foreach (Column c in t.PrimaryKeyColumns.OrderBy(x => x.Name))
						{
							if (!pkList.ContainsKey(c.Name.ToLower()))
								return false;
							if (pkList[c.Name.ToLower()].DataType != c.DataType)
								return false;
						}
					}
				}

				//Ensure that all tables in inheritance hierarchy
				//do not have duplicate column names except primary keys
				List<string> columNames = new List<string>();
				foreach (Table t in inheritTables)
				{
					foreach (Reference r in t.Columns)
					{
						Column c = (Column)r.Object;
						//Make sure this is not a PK
						if (!pkList.ContainsKey(c.Name.ToLower()))
						{
							//If the column already exists then it is a duplicate
							if (columNames.Contains(c.Name.ToLower()))
								return false;

							columNames.Add(c.Name.ToLower());
						}
					}
				}

				return true;
			}
		}

		/// <summary>
		/// Get the full hierarchy of tables starting with this table 
		/// and working back to the most base table
		/// </summary>
		/// <returns></returns>
		public List<Table> GetTableHierarchy()
		{
			List<Table> retval = new List<Table>();			
			Table t = this;
			while (t != null)
			{
				retval.Add(t);
				t = t.ParentTable;
			}
			retval.Reverse();
			return retval;
		}

		/// <summary>
		/// Determines if any base class has its Immutable set to true
		/// </summary>
		[Browsable(false)]
		public bool AnyBaseNonModifiable
		{
			get
			{
				List<Table> tList = this.GetTableHierarchy();
				foreach (Table t in tList)
				{
					if (t.Immutable)
						return true;
				}
				return false;
			}
		}

		public bool PropertyExistsInBase(string columnName)
		{
			ColumnCollection cList =  GetColumnsFullHierarchy(false);
			foreach (Column c in cList)
			{
				if (string.Compare(c.Name, columnName, true) == 0)
					return true;
			}
			return false;
		}

		/// <summary>
		/// This gets all columns from this and all base classes
		/// </summary>
		/// <returns></returns>
		public ColumnCollection GetColumnsFullHierarchy()
		{
			return GetColumnsFullHierarchy(true);
		}

		/// <summary>
		/// This gets all columns from this and all base classes
		/// </summary>
		/// <returns></returns>
		public ColumnCollection GetColumnsFullHierarchy(bool includeCurrent)
		{
			try
			{
				List<string> nameList = new List<string>();
				ColumnCollection retval = new ColumnCollection(this.Root);

				Table t = this;
				if (!includeCurrent) t = t.ParentTable;
				while (t != null)
				{
					foreach (Reference r in t.Columns)
					{
						Column c = (Column)r.Object;
						if (!nameList.Contains(c.Name.ToLower()))
						{
							nameList.Add(c.Name.ToLower());
							retval.Add(c);
						}
					}
					t = t.ParentTable;
				}
				return retval;

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		/// <summary>
		/// This gets all table composites from this and all base classes
		/// </summary>
		/// <returns></returns>
		public List<TableComposite> GetTableCompositesFullHierarchy(bool includeCurrent)
		{
			try
			{
				List<TableComposite> retval = new List<TableComposite>();

				Table t = this;
				if (!includeCurrent) t = t.ParentTable;
				while (t != null)
				{
					foreach (TableComposite tableComposite in t.CompositeList)
					{
						retval.Add(tableComposite);
					}
					t = t.ParentTable;
				}
				return retval;

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		/// <summary>
		/// This gets all table components from this and all base classes
		/// </summary>
		/// <returns></returns>
		public List<TableComponent> GetTableComponentsFullHierarchy(bool includeCurrent)
		{
			try
			{
				List<TableComponent> retval = new List<TableComponent>();

				Table t = this;
				if (!includeCurrent) t = t.ParentTable;
				while (t != null)
				{
					foreach (TableComponent tableComponent in t.ComponentList)
					{
						retval.Add(tableComponent);
					}
					t = t.ParentTable;
				}
				return retval;

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		/// <summary>
		/// This gets all columns in this class NOT in a base class
		/// </summary>
		/// <returns></returns>
		public ColumnCollection GetColumnsNotInBase()
		{
			try
			{
				List<string> nameList = new List<string>();
				ColumnCollection fullList = GetColumnsFullHierarchy(false);

				List<Column> currentList = new List<Column>();
				foreach (Column c in this.GetColumns())
					currentList.Add(c);

				List<Column> delList = new List<Column>();
				foreach (Column c in currentList)
				{
					if (fullList[c.Name] != null)
					{
						delList.Add(c);
					}
				}

				foreach (Column c in delList)
				{
					currentList.Remove(c);
				}

				ColumnCollection retval = new ColumnCollection(this.Root);
				foreach (Column c in currentList)
					retval.Add(c);
				return retval;

			}
			catch (Exception ex)
			{
				throw;
			}
		}

		public IEnumerable<Table> GetParentTables()
		{
			List<Table> retval = new List<Table>();
			foreach (Relation r in this.AllRelationships)
			{
				if (r.ChildTableRef.Object == this)
				{
					retval.Add((Table)r.ParentTableRef.Object);
				}
			}

			return retval;
		}

		public ColumnCollection GetColumnInRelationships()
		{
			ColumnCollection retval = new ColumnCollection(this.Root);
			foreach (Relation r in ((ModelRoot)this.Root).Database.Relations)
			{
				if (r.ParentTableRef.Object == this)
				{
					foreach (ColumnRelationship cr in r.ColumnRelationships)
					{
						Column column = (Column)cr.ParentColumnRef.Object;
						if (!retval.Contains(column))
							retval.Add(column);
					}
				}
				else if (r.ChildTableRef.Object == this)
				{
					foreach (ColumnRelationship cr in r.ColumnRelationships)
					{
						Column column = (Column)cr.ChildColumnRef.Object;
						if (!retval.Contains(column))
							retval.Add(column);
					}
				}
			}			
			return retval;
		}

		public IEnumerable<Column> GetColumnNotInRelationships()
		{
			try
			{
				ColumnCollection inRelations = this.GetColumnInRelationships();
				ColumnCollection retval = new ColumnCollection(this.Root);
				foreach (Column c in GetColumns())
				{
					if (!inRelations.Contains(c))
						retval.Add(c);
				}
				return retval.OrderBy(x => x.Name);
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		/// <summary>
		/// Returns the columns for this table only (not hierarchy)
		/// </summary>
		/// <returns></returns>
		public IEnumerable<Column> GetColumns()
		{
			try
			{
				List<Column> list = new List<Column>();
				foreach (Reference r in this.Columns)
				{
					list.Add((Column)r.Object);
				}
				return list.OrderBy(x => x.Name);
			}
			catch (Exception ex)
			{
				throw;
			}
		}

		public List<Column> GetColumnsByType(System.Data.SqlDbType type)
		{
			List<Column> retval = new List<Column>();
			foreach (Column column in this.GetColumnsFullHierarchy())
			{
				if (column.DataType == type)
				{
					retval.Add(column);
				}
			}
			return retval;
		}

		public List<Relation> GetRelationsFullHierarchy()
		{
			try
			{
				List<Relation> allRelations = new List<Relation>();
				List<Table> allTables = this.GetTableHierarchy();
				foreach (Table table in allTables)
				{
					foreach (Relation relation in table.AllRelationships)
					{
						allRelations.Add(relation);
					}
				}
				return allRelations;
			}
			catch (Exception ex)
			{				
				throw;
			}
		}

		public RelationCollection GetRelations()
		{
			try
			{
				RelationCollection retval = new RelationCollection(this.Root);
				foreach (Reference r in this.Relationships)
				{
					if (r.Object != null)
						retval.Add((Relation)r.Object);
				}
				return retval;

			}
			catch (Exception ex)
			{				
				throw;
			}
		}

		internal void PostLoad()
		{
			foreach (int id in _unitTestTableIdPreLoad)
			{
				Table[] tArray = ((ModelRoot)this.Root).Database.Tables.GetById(id);
				if (tArray.Length == 1)
				{
					_unitTestDependencies.Add(tArray[0]);
				}
			}
			_unitTestTableIdPreLoad.Clear();
		}

		public bool IsColumnInherited(Column column)
		{
			ColumnCollection allInheritedColumns = this.GetColumnsFullHierarchy(false);
			var q = from x in allInheritedColumns
							where x.PascalName == column.PascalName
							select x;
			return q.FirstOrDefault() != null;
		}

		public string ToDatabaseIdentifier()
		{
			return ValidationHelper.MakeDatabaseIdentifier(this.DatabaseName);
		}

		/// <summary>
		/// Create a valid T-SQL variable from the name
		/// </summary>
		/// <returns></returns>
		public string ToDatabaseCodeIdentifier()
		{
			return ValidationHelper.MakeDatabaseScriptIdentifier(this.DatabaseName);
		}

    #endregion

    #region IXMLable Members

    public override void XmlAppend(XmlNode node)
    {
      try
      {
        XmlDocument oDoc = node.OwnerDocument;

				XmlHelper.AddAttribute(node, "key", this.Key);
				XmlHelper.AddAttribute(node, "name", this.Name);
				XmlHelper.AddAttribute(node, "dbschema", this.DBSchema);

        XmlAttribute codeFacade = oDoc.CreateAttribute("codeFacade");
        codeFacade.Value = this.CodeFacade;
        node.Attributes.Append(codeFacade);

        XmlAttribute description = oDoc.CreateAttribute("description");
        description.Value = this.Description;
        node.Attributes.Append(description);

        XmlNode relationshipsNode = oDoc.CreateElement("relationships");
        this.Relationships.XmlAppend(relationshipsNode);
        node.AppendChild(relationshipsNode);

        XmlNode columnsNode = oDoc.CreateElement("columns");
        this.Columns.XmlAppend(columnsNode);
        node.AppendChild(columnsNode);

				XmlNode unitTestNode = oDoc.CreateElement("unitTestDependencies");
				node.AppendChild(unitTestNode);
				foreach (Table t in this.UnitTestDependencies)
				{
					XmlHelper.AddElement((XmlElement)unitTestNode, "tableid", t.Id.ToString());					
				}

				XmlNode compositesNode = oDoc.CreateElement("composites");
				this.CompositeList.XmlAppend(compositesNode);
				node.AppendChild(compositesNode);

				XmlNode componentsNode = oDoc.CreateElement("components");
				this.ComponentList.XmlAppend(componentsNode);
				node.AppendChild(componentsNode);

        XmlNode customRetrieveRulesNode = oDoc.CreateElement("customretrieverules");
        this.CustomRetrieveRules.XmlAppend(customRetrieveRulesNode);
        node.AppendChild(customRetrieveRulesNode);

				XmlAttribute generated = oDoc.CreateAttribute("generated");
				generated.Value = this.Generated.ToString();
				node.Attributes.Append(generated);

				XmlAttribute immutable = oDoc.CreateAttribute("immutable");
				immutable.Value = this.Immutable.ToString();
				node.Attributes.Append(immutable);

				XmlAttribute enforePrimaryKey = oDoc.CreateAttribute("enforePrimaryKey");
				enforePrimaryKey.Value = this.EnforcePrimaryKey.ToString();
				node.Attributes.Append(enforePrimaryKey);

				XmlAttribute allowUnitTest = oDoc.CreateAttribute("allowUnitTest");
				allowUnitTest.Value = this.AllowUnitTest.ToString();
				node.Attributes.Append(allowUnitTest);

        XmlAttribute modifiedAudit = oDoc.CreateAttribute("modifiedAudit");
        modifiedAudit.Value = this.AllowModifiedAudit.ToString();
        node.Attributes.Append(modifiedAudit);

        XmlAttribute isTypeTable = oDoc.CreateAttribute("isTypeTable");
        isTypeTable.Value = this.IsTypeTable.ToString();
        node.Attributes.Append(isTypeTable);

        XmlAttribute createAudit = oDoc.CreateAttribute("createAudit");
        createAudit.Value = this.AllowCreateAudit.ToString();
        node.Attributes.Append(createAudit);

        XmlAttribute timestamp = oDoc.CreateAttribute("timestamp");
        timestamp.Value = this.AllowTimestamp.ToString();
        node.Attributes.Append(timestamp);
        XmlAttribute id = oDoc.CreateAttribute("id");
        id.Value = this.Id.ToString();
        node.Attributes.Append(id);

        XmlNode staticDataNode = oDoc.CreateElement("staticData");
        StaticData.XmlAppend(staticDataNode);
        node.AppendChild(staticDataNode);

        XmlAttribute associativeTable = oDoc.CreateAttribute("associativeTable");
        associativeTable.Value = this.AssociativeTable.ToString();
        node.Attributes.Append(associativeTable);

        XmlAttribute hasHistory = oDoc.CreateAttribute("hasHistory");
        hasHistory.Value = this.HasHistory.ToString();
        node.Attributes.Append(hasHistory);

        XmlAttribute createMetaData = oDoc.CreateAttribute("createMetaData");
        createMetaData.Value = this.CreateMetaData.ToString();
        node.Attributes.Append(createMetaData);

        XmlAttribute fullIndexSearch = oDoc.CreateAttribute("fullIndexSearch");
        fullIndexSearch.Value = this.FullIndexSearch.ToString();
        node.Attributes.Append(fullIndexSearch);

				XmlAttribute created = oDoc.CreateAttribute("createdDate");
				created.Value = _createdDate.ToString("yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
				node.Attributes.Append(created);

				XmlAttribute allowAuditTracking = oDoc.CreateAttribute("allowAuditTracking");				
				allowAuditTracking.Value = this.AllowAuditTracking.ToString();
				node.Attributes.Append(allowAuditTracking);

				if (this.ParentTable != null)
				{
					XmlAttribute parentTable = oDoc.CreateAttribute("parentTableKey");
					parentTable.Value = this.ParentTableKey;
					node.Attributes.Append(parentTable);
				}

      }
      catch(Exception ex)
      {
        throw;
      }

    }

    public override void XmlLoad(XmlNode node)
    {
      try
      {
        XmlNode relationshipsNode = node.SelectSingleNode("relationships");
        Relationships.XmlLoad(relationshipsNode);

        XmlNode columnsNode = node.SelectSingleNode("columns");
				if (columnsNode != null)
					this.Columns.XmlLoad(columnsNode);

				XmlNode compositesNode = node.SelectSingleNode("composites");
				if (compositesNode != null)
					this.CompositeList.XmlLoad(compositesNode);

				XmlNode componentsNode = node.SelectSingleNode("components");
				if (componentsNode != null)
					this.ComponentList.XmlLoad(componentsNode);

        XmlNode customRetrieveRulesNode = node.SelectSingleNode("customretrieverules");
        if(customRetrieveRulesNode != null)
          this.CustomRetrieveRules.XmlLoad(customRetrieveRulesNode);

				this.Generated = XmlHelper.GetAttributeValue(node, "generated", _def_generated);				
				this.Immutable = XmlHelper.GetAttributeValue(node, "immutable", _def_immutable);
				this.EnforcePrimaryKey = XmlHelper.GetAttributeValue(node, "enforePrimaryKey", _def_enforePrimaryKey);
				this.AllowUnitTest = (UnitTestSettingsConstants)Enum.Parse(typeof(UnitTestSettingsConstants), XmlHelper.GetAttributeValue(node, "allowUnitTest", _def_allowUnitTest.ToString()), true);				

        this.SetId(XmlHelper.GetAttributeValue(node, "id", _id));

        XmlNode staticDataNode = node.SelectSingleNode("staticData");
        this.StaticData.XmlLoad(staticDataNode);

				XmlNode unitTestNode = node.SelectSingleNode("unitTestDependencies");
				if (unitTestNode != null)
				{
					foreach (XmlNode n in unitTestNode.ChildNodes)
					{
						_unitTestTableIdPreLoad.Add(int.Parse(n.InnerText));
					}
				}

        this.AssociativeTable = XmlHelper.GetAttributeValue(node ,"associativeTable", _associativeTable);
        this.HasHistory = XmlHelper.GetAttributeValue(node, "hasHistory", _hasHistory);
        this.CreateMetaData = XmlHelper.GetAttributeValue(node, "createMetaData", _def_createMetaData);
        this.FullIndexSearch = XmlHelper.GetAttributeValue(node, "fullIndexSearch", _def_fullIndexSearch);

				_key = XmlHelper.GetAttributeValue(node, "key", _key);
				this.Name = XmlHelper.GetAttributeValue(node, "name", "");
				this.DBSchema = XmlHelper.GetAttributeValue(node, "dbschema", "");
				this.CodeFacade = XmlHelper.GetAttributeValue(node, "codeFacade", "");
				this.Description = node.Attributes["description"].Value;
				this.AllowModifiedAudit = XmlHelper.GetAttributeValue(node, "modifiedAudit", _modifiedAudit);
				this.AllowCreateAudit = XmlHelper.GetAttributeValue(node, "createAudit", _def_createAudit);
				this.IsTypeTable = XmlHelper.GetAttributeValue(node, "isTypeTable", _isTypeTable);
				_createdDate = DateTime.ParseExact(XmlHelper.GetAttributeValue(node, "createdDate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture)), "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
				this.AllowTimestamp = XmlHelper.GetAttributeValue(node, "timestamp", _allowTimestamp);
				this.AllowAuditTracking = XmlHelper.GetAttributeValue(node, "allowAuditTracking", _def_allowAuditTracking);
				_parentTableKey = XmlHelper.GetAttributeValue(node, "parentTableKey", "");

        this.Dirty = false;
      }
      catch(Exception ex)
      {
        throw;
      }
    }

    #endregion

    #region Helpers

    public Reference CreateRef()
    {
      Reference returnVal = new Reference(this.Root);
      returnVal.Ref = this.Id;
      returnVal.RefType = ReferenceType.Table;
      return returnVal;
    }

    [Browsable(false)]
    public string CamelName
    {
			//get { return StringHelper.DatabaseNameToCamelCase(this.Name); }
			get { return StringHelper.DatabaseNameToCamelCase(this.PascalName); }
		}

		[Browsable(false)]
		public string PascalName
		{
			get
			{
				if ((this.CodeFacade != "") && (((ModelRoot)this.Root).TransformNames))
					return StringHelper.DatabaseNameToPascalCase(this.CodeFacade);
				else if ((this.CodeFacade == "") && (((ModelRoot)this.Root).TransformNames))
					return StringHelper.DatabaseNameToPascalCase(this.Name);
				if ((this.CodeFacade != "") && !(((ModelRoot)this.Root).TransformNames))
					return this.CodeFacade;
				else if ((this.CodeFacade == "") && !(((ModelRoot)this.Root).TransformNames))
					return this.Name;
				return this.Name; //Default
			}
		}

    [Browsable(false)]
    public string DatabaseName
    {
      get { return this.Name; }
    }

    [Browsable(false)]
    public ReadOnlyCollection<Relation> ParentRoleRelations
    {
      get
      {
        try
        {
					List<Relation> retval = new List<Relation>();
          foreach(Relation relation in ((ModelRoot)this.Root).Database.Relations)
          {
            if((relation.ParentTableRef.Object != null) && (relation.ParentTableRef.Ref == this.Id))
              retval.Add(relation);
          }
          return retval.AsReadOnly();
        }
        catch(Exception ex)
        {
          throw;
        }
      }
    }

    [Browsable(false)]
		public ReadOnlyCollection<Relation> ChildRoleRelations
    {
      get
      {
				List<Relation> retval = new List<Relation>();
        foreach(Relation relation in ((ModelRoot)this.Root).Database.Relations)
        {
          if((relation.ChildTableRef.Object != null) && (relation.ChildTableRef.Ref == this.Id))
            retval.Add(relation);
        }
        return retval.AsReadOnly();
      }
    }

    [Browsable(false)]
    public bool SelfReference
    {
			//get
			//{
			//  foreach (Relation rel in this.AllRelationships)
			//  {
			//    if(rel.ParentTableRef.Ref == rel.ChildTableRef.Ref)
			//      return true;
			//  }
			//  return false;
			//}
			get { return this.SelfReferenceRelation != null; }
    }

    [Browsable(false)]
    public List<Table> RelatedTables
    {
      get
      {
				List<Table> relatedTables = new List<Table>();
				foreach (Relation relation in this.GetRelationsFullHierarchy())				
        {          
          Table childTable = (Table)relation.ChildTableRef.Object;
          Table parentTable = (Table)relation.ParentTableRef.Object;
          if (childTable != this && !relatedTables.Contains(childTable))
          {
            relatedTables.Add(childTable);
          }
          if (parentTable != this && !relatedTables.Contains(parentTable))
          {
            relatedTables.Add(parentTable);
          }
        }
        return relatedTables;
      }
    }


		////TODO: Make this work for compound primary keys
		//[Browsable(false)]
		//public Column SelfReferencePrimaryKeyColumn
		//{
		//  get { return (Column)this.PrimaryKeyColumns[0]; }
		//}

		//[Browsable(false)]
		//public IEnumerable<Column> SelfReferenceParentColumns
		//{
		//  get
		//  {
		//    List<Column> retval = new List<Column>();
		//    foreach (Relation relation in this.AllRelationships)
		//    {
		//      Table child = (Table)relation.ChildTableRef.Object;
		//      Table parent = (Table)relation.ParentTableRef.Object;
		//      if (child == parent)
		//      {
		//        foreach (Column item in relation.FkColumns)
		//          retval.Add(item);
		//      }
		//    }
		//    return retval;
		//  }
		//}

		[Browsable(false)]
		public Relation SelfReferenceRelation
		{
			get { return this.AllRelationships.Where(x => x.ChildTableRef.Object == x.ParentTableRef.Object).FirstOrDefault(); }
		}

    [
    Browsable(false),
    Description("Determines the fields that constitute the table primary key."),
    Category("Data"),
    DefaultValue(""),
    Editor(typeof(Widgetsphere.Generator.Design.Editors.NullEditor), typeof(System.Drawing.Design.UITypeEditor)),
    TypeConverter(typeof(Widgetsphere.Generator.Design.Converters.TablePrimaryKeyConverter)),
    ]
    public IList<Column> PrimaryKeyColumns
    {
      get
      {
				List<Column> primaryKeyColumns = new List<Column>();
				foreach (Reference columnRef in this.Columns)
				{
					Column column = (Column)columnRef.Object;
					if (column.PrimaryKey) primaryKeyColumns.Add(column);
				}
        return primaryKeyColumns.AsReadOnly();
      }
    }

		[Browsable(true)]
		[Category("Data")]
		[Description("The date that this object was created.")]
		[ReadOnlyAttribute(true)]
		public DateTime CreatedDate
		{
			get { return _createdDate; }
		}

    protected internal void SetId(int id)
    {
      _id = id;
    }

		protected internal void SetKey(string key)
		{
			_key = key;
		}

		[Browsable(false)]
		public string CorePropertiesHash
		{
			get
			{
				string prehash =
					this.Name + "|" +
					this.DBSchema;
				return prehash;
			}
		}

    #endregion

    #region ICodeFacadeObject Members

    [
    Browsable(true),
    Description("Determines the object name used in the API. If this property is blank the 'Name' property is used in the API. This property can be used to mask the database identifier."),
    Category("Design"),
    DefaultValue(""),
    ]
    public string CodeFacade
    {
      get { return _codeFacade; }
      set
      {
        _codeFacade = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("codeFacade"));
      }
    }

    public string GetCodeFacade()
    {
      if (this.CodeFacade == "")
        return this.Name;
      else
        return this.CodeFacade;
    }

    #endregion

  }
}